import json
import string
import random
import datetime
from django.contrib.auth import get_user_model
from rest_framework import serializers
from wechatpy.exceptions import WeChatOAuthException
from wechatpy.utils import check_wxa_signature
from wechatpy.exceptions import WeChatPayException
from rest_framework_jwt.settings import api_settings
from .mini_base import wechat_client, wx_pay, wx_pay_howho, wechat_client_howhow
from .authentication import jwt_payload_handler
from .models import MiniWxUserInfo, WxPayOrder
from .WXBizDataCrypt import WXBizDataCrypt
from core.tools.func_utils import funcUtils
from .serializers import BasePaySerializer
from finance_c2c.local_settings import KaLaiBaoConfig
from apps.user_operation.tasks import task_new_user_coupon

User = get_user_model()

jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


# 微信登录
class WXLoginSerializer(serializers.Serializer):
    rawData = serializers.CharField(label="前端拿到的用户信息", help_text="前端拿到的用户信息")
    signature = serializers.CharField(label="前端用户信息中signature", help_text="前端用户信息中signature")
    encryptedData = serializers.CharField(label="包括敏感数据在内的完整用户信息的加密数据", help_text="包括敏感数据在内的完整用户信息的加密数据",
                                          required=False, allow_null=True)
    iv = serializers.CharField(label="加密算法的初始向量", help_text="加密算法的初始向量", allow_null=False)
    code = serializers.CharField(allow_null=False, label="微信code", help_text="微信code")

    def validate_code(self, code):
        try:
            res = wechat_client.wxa.code_to_session(code)
        except WeChatOAuthException as e:
            raise serializers.ValidationError(e.errcode)
        return res

    def validate(self, attrs):
        res = attrs["code"]
        session_key = res.get("session_key")
        client_signature = attrs["signature"]
        raw_data = attrs["rawData"]
        try:
            check_wxa_signature(session_key, raw_data, client_signature)
        except WeChatOAuthException as e:
            raise serializers.ValidationError(e.errcode)
        return attrs

    def create(self, validated_data):
        res = validated_data["code"]
        openid = res.get("openid")
        session_key = res.get("session_key")
        rawData = validated_data["rawData"]
        rawData = json.loads(rawData)
        nick_name = rawData.get("nickName")
        head_url = rawData.get("avatarUrl")
        sex = rawData.get("gender")
        country = rawData.get("country")
        city = rawData.get("city")
        wx_user_info, created = MiniWxUserInfo.objects.get_or_create(openid=openid)
        wx_user_info.session_key = session_key
        wx_user_info.nick_name = nick_name
        wx_user_info.head_url = head_url
        wx_user_info.sex = sex
        wx_user_info.country = country
        wx_user_info.city = city
        wx_user_info.update_time = datetime.datetime.now()
        wx_user_info.save()
        # encryptedData = validated_data["encryptedData"]
        # iv = validated_data["iv"]
        # pc = WXBizDataCrypt(miniAppId, session_key)
        # wx_info = pc.decrypt(encryptedData, iv)
        if hasattr(wx_user_info, "userprofile"):
            user = wx_user_info.userprofile
            # coffee 项目注册进来更新优惠券
            from apps.coffee.models import GiveRecord
            GiveRecord.objects.new_user_login(user)
            payload = jwt_payload_handler(self, user, mini=True)
            print(payload, "payload")
            token = jwt_encode_handler(payload)
            setattr(self, 'object', {"user": user, "token": token})
            return wx_user_info
        else:
            setattr(self, 'object', {"openid": openid})
            return openid

    def update(self, instance, validated_data):
        pass

    class Meta:
        fields = ("encryptedData", "iv", "rawData", "signature", "code")


class WXLoginSerializerV2(serializers.Serializer):
    rawData = serializers.CharField(label="前端拿到的用户信息", help_text="前端拿到的用户信息")
    signature = serializers.CharField(label="前端用户信息中signature", help_text="前端用户信息中signature")
    encryptedData = serializers.CharField(label="包括敏感数据在内的完整用户信息的加密数据", help_text="包括敏感数据在内的完整用户信息的加密数据",
                                          required=False, allow_null=True)
    iv = serializers.CharField(label="加密算法的初始向量", help_text="加密算法的初始向量", allow_null=False)
    code = serializers.CharField(allow_null=False, label="微信code", help_text="微信code")

    def validate_code(self, code):
        try:
            res = wechat_client_howhow.wxa.code_to_session(code)
        except WeChatOAuthException as e:
            raise serializers.ValidationError(e.errcode)
        return res

    def validate(self, attrs):
        res = attrs["code"]
        session_key = res.get("session_key")
        client_signature = attrs["signature"]
        raw_data = attrs["rawData"]
        try:
            check_wxa_signature(session_key, raw_data, client_signature)
        except WeChatOAuthException as e:
            raise serializers.ValidationError(e.errcode)
        return attrs

    def create(self, validated_data):
        res = validated_data["code"]
        openid = res.get("openid")
        session_key = res.get("session_key")
        rawData = validated_data["rawData"]
        rawData = json.loads(rawData)
        nick_name = rawData.get("nickName")
        head_url = rawData.get("avatarUrl")
        sex = rawData.get("gender")
        country = rawData.get("country")
        city = rawData.get("city")
        wx_user_info, created = MiniWxUserInfo.objects.get_or_create(openid=openid)
        wx_user_info.session_key = session_key
        wx_user_info.nick_name = nick_name
        wx_user_info.head_url = head_url
        wx_user_info.sex = sex
        wx_user_info.country = country
        wx_user_info.city = city
        wx_user_info.update_time = datetime.datetime.now()
        wx_user_info.save()
        # encryptedData = validated_data["encryptedData"]
        # iv = validated_data["iv"]
        # pc = WXBizDataCrypt(miniAppId, session_key)
        # wx_info = pc.decrypt(encryptedData, iv)
        if hasattr(wx_user_info, "userprofile"):
            user = wx_user_info.userprofile
            # coffee 项目注册进来更新优惠券
            from apps.coffee.models import GiveRecord
            GiveRecord.objects.new_user_login(user)
            payload = jwt_payload_handler(self, user, mini=True)
            print(payload, "payload")
            token = jwt_encode_handler(payload)
            setattr(self, 'object', {"user": user, "token": token})
            return wx_user_info
        else:
            setattr(self, 'object', {"openid": openid})
            return openid

    def update(self, instance, validated_data):
        pass

    class Meta:
        fields = ("encryptedData", "iv", "rawData", "signature", "code")


# 微信手机号解密
class TelEncryptedSerializer(serializers.Serializer):
    encryptedData = serializers.CharField(required=True, allow_null=False, label="包括敏感数据在内的完整用户信息的加密数据",
                                          write_only=True)
    iv = serializers.CharField(label="加密算法的初始向量", help_text="加密算法的初始向量", write_only=True)
    openid = serializers.CharField(label="openid", help_text="openid", write_only=True, required=True,
                                   allow_blank=False, allow_null=False)
    channel_key = serializers.CharField(write_only=True, label="渠道key", allow_null=True, allow_blank=True,
                                        required=False)

    def validate_openid(self, openid):
        try:
            wx_user = MiniWxUserInfo.objects.get(openid=openid)
        except Exception as e:
            raise serializers.ValidationError("OPENID ERROR")
        return wx_user

    def validate_channel_key(self, channel_key):
        from apps.coffee.models import Channel
        try:
            return Channel.objects.get(key=channel_key)
        except Exception as e:
            return Channel.objects.get(key="iamcoffee")

    def validate(self, attrs):
        wx_user = attrs["openid"]
        session_key = wx_user.session_key
        encryptedData = attrs["encryptedData"]
        iv = attrs["iv"]
        pc = WXBizDataCrypt(KaLaiBaoConfig.miniAppId, session_key)
        wx_info = pc.decrypt(encryptedData, iv)
        print(wx_info, "手机号 wx_info")
        attrs["wx_info"] = wx_info
        return attrs

    def create(self, validated_data):
        wx_info = validated_data["wx_info"]
        wx_mini_user = validated_data["openid"]
        coffee_channel = validated_data["channel_key"]
        channel_key = coffee_channel.key
        mobile = wx_info.get("phoneNumber")
        user, created = User.objects.get_or_create(mobile=mobile, username=mobile)
        user.wx_mini_user = wx_mini_user
        user.coffee_channel = coffee_channel
        user.save()
        task_new_user_coupon.delay(user_id=user.id, channel_key=channel_key)
        payload = jwt_payload_handler(self, user, mini=True)
        token = jwt_encode_handler(payload)
        setattr(self, 'object', {"user": user, "token": token})
        # coffee 项目注册进来更新优惠券
        # 查看转赠记录，找到需要更新的coffee券
        from apps.coffee.models import GiveRecord
        GiveRecord.objects.new_user_login(user)
        return user

    class Meta:
        fields = ("encryptedData", "iv", "openid")


class V2TelEncryptedSerializer(serializers.Serializer):
    encryptedData = serializers.CharField(required=True, allow_null=False, label="包括敏感数据在内的完整用户信息的加密数据",
                                          write_only=True)
    iv = serializers.CharField(label="加密算法的初始向量", help_text="加密算法的初始向量", write_only=True)
    openid = serializers.CharField(label="openid", help_text="openid", write_only=True, required=True,
                                   allow_blank=False, allow_null=False)
    channel_key = serializers.CharField(write_only=True, label="渠道key", allow_null=True, allow_blank=True,
                                        required=False)

    def validate_openid(self, openid):
        try:
            wx_user = MiniWxUserInfo.objects.get(openid=openid)
        except Exception as e:
            raise serializers.ValidationError("OPENID ERROR")
        return wx_user

    def validate_channel_key(self, channel_key):
        from apps.coffee.models import Channel
        try:
            return Channel.objects.get(key=channel_key)
        except Exception as e:
            return Channel.objects.get(key="iamcoffee")

    def validate(self, attrs):
        wx_user = attrs["openid"]
        session_key = wx_user.session_key
        encryptedData = attrs["encryptedData"]
        iv = attrs["iv"]
        pc = WXBizDataCrypt(KaLaiBaoConfig.miniAppId, session_key)
        wx_info = pc.decrypt(encryptedData, iv)
        print(wx_info, "手机号 wx_info")
        attrs["wx_info"] = wx_info
        return attrs

    def create(self, validated_data):
        wx_info = validated_data["wx_info"]
        wx_mini_user = validated_data["openid"]
        coffee_channel = validated_data["channel_key"]
        channel_key = coffee_channel.key
        mobile = wx_info.get("phoneNumber")
        user, created = User.objects.get_or_create(mobile=mobile, username=mobile)
        user.wx_mini_user = wx_mini_user
        user.coffee_channel = coffee_channel
        user.save()
        task_new_user_coupon.delay(user_id=user.id, channel_key=channel_key)
        payload = jwt_payload_handler(self, user, mini=True)
        token = jwt_encode_handler(payload)
        setattr(self, 'object', {"user": user, "token": token})
        # coffee 项目注册进来更新优惠券
        # 查看转赠记录，找到需要更新的coffee券
        from apps.coffee.models import GiveRecord
        GiveRecord.objects.new_user_login(user)
        return user

    class Meta:
        fields = ("encryptedData", "iv", "openid")

# 统一下单
class WeChatOrderSerializer(BasePaySerializer):
    wxPayInstance = wx_pay

    def create(self, validated_data):
        body = "ERROR"
        total_fee = 0
        order = validated_data["orderNo"]
        user = validated_data["user"]
        openid = user.wx_mini_user.openid
        mch_id = KaLaiBaoConfig.mch_id
        noticePayUrl = KaLaiBaoConfig.miniNoticePayUrl
        if validated_data["model"] == "coffee":
            body = "咖啡支付"
            total_fee = order.payment
        self.payData = {"body": body, "total_fee": total_fee, "openid": openid, "mch_id": mch_id,
                        "noticePayUrl": noticePayUrl, "trade_type": "JSAPI"}
        goods_tag = order.coffee_client.goods_tag
        if goods_tag:
            self.payData["goods_tag"] = goods_tag
        print(self.payData, "WeChatOrderSerializer")
        wx_order_instance, response = super(WeChatOrderSerializer, self).create(validated_data)
        return wx_order_instance

    class Meta:
        fields = ("user", "orderNo", "model")


class WeChatOrderSerializerV2(BasePaySerializer):
    wxPayInstance = wx_pay_howho

    def create(self, validated_data):
        body = "ERROR"
        total_fee = 0
        order = validated_data["orderNo"]
        user = validated_data["user"]
        openid = user.wx_mini_user.openid
        mch_id = KaLaiBaoConfig.mch_id
        noticePayUrl = KaLaiBaoConfig.miniNoticePayUrl
        if validated_data["model"] == "coffee":
            body = "咖啡支付"
            total_fee = order.payment
        self.payData = {"body": body, "total_fee": total_fee, "openid": openid, "mch_id": mch_id,
                        "noticePayUrl": noticePayUrl, "trade_type": "JSAPI"}
        goods_tag = order.coffee_client.goods_tag
        if goods_tag:
            self.payData["goods_tag"] = goods_tag
        print(self.payData, "WeChatOrderSerializer")
        wx_order_instance, response = super(WeChatOrderSerializerV2, self).create(validated_data)
        return wx_order_instance

    class Meta:
        fields = ("user", "orderNo", "model")
